﻿Imports System.IO
Imports System.Drawing
Imports System.ComponentModel
''' <summary>
''' 文档内容处理类
''' </summary>
''' <remarks></remarks>
Partial Public Class Document
#Region "属性"
    ''' <summary>
    ''' 最大行宽度
    ''' </summary>
    ''' <remarks></remarks>
    Public MaxWidth As Integer
    ''' <summary>
    ''' 最大行宽列表
    ''' </summary>
    ''' <remarks></remarks>
    Public MaxWidthLines As New List(Of Integer)
    ''' <summary>
    ''' 撤销重做管理器
    ''' </summary>
    ''' <remarks></remarks>
    Public StepList As New StepManager
    ''' <summary>
    ''' 表示行管理器
    ''' </summary>
    ''' <remarks></remarks>
    Public ExDisplayManager As DisplayLineManager
    ''' <summary>
    ''' 实际行管理器
    ''' </summary>
    ''' <remarks></remarks>
    Public ExRealLineManager As RealLineManager
    ''' <summary>
    ''' 编码
    ''' </summary>
    ''' <remarks></remarks>
    Dim mEncoding As System.Text.Encoding = Encoding.Default
    <Description("文档的编码")> _
    Property Encoding() As System.Text.Encoding
        Get
            Return mEncoding
        End Get
        Set(ByVal value As System.Text.Encoding)
            mEncoding = value
        End Set
    End Property
    Private mInputBytePosition As Point
    ''' <summary>
    ''' 行列信息（字节）
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    ReadOnly Property InputBytePosition() As Point
        Get
            Return mInputBytePosition
        End Get
    End Property
    Private mInputPosition As Point
    ''' <summary>
    ''' 行列信息（字符）
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    <Description("文档的插入点")> _
    Public Property InputPosition() As Point
        Get
            Return mInputPosition
        End Get
        Set(ByVal value As Point)
            mInputPosition = value
            mInputBytePosition.Y = value.Y
            If mInputPosition.X > 1 Then
                Dim strText As String = Mid(GetRealLineText(mInputPosition.Y), 1, mInputPosition.X - 1)
                mInputBytePosition.X = Encoding.GetByteCount(strText) + 1
            Else
                mInputBytePosition.X = 1
            End If
        End Set
    End Property
    Private mDisplayPosition As Point
    ''' <summary>
    ''' 表示行列信息
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property DisplayPosition() As Point
        Get
            Return mDisplayPosition
        End Get
        Set(ByVal value As Point)
            mDisplayPosition = value
            InputPosition = GetInputPosByDisplayPos(value)
        End Set
    End Property
    ''' <summary>
    ''' 是否有选择区域
    ''' </summary>
    ''' <remarks></remarks>
    ReadOnly Property HasSelection() As Boolean
        Get
            If SelectStartRealPos.X = 0 Then Return False
            If ComparePoint(SelectStartRealPos, SelectEndRealPos) = CompareResult.Equal Then Return False
            Return True
        End Get
    End Property
    ''' <summary>
    ''' 高亮关键字
    ''' </summary>
    ''' <remarks></remarks>
    Private mHeightLightWord As String
#End Region
#Region "行信息"
    ''' <summary>
    ''' 内存行信息
    ''' </summary>
    ''' <remarks></remarks>
    Public MemoryLines As New List(Of Line)
    ''' <summary>
    ''' 最大内存行数
    ''' </summary>
    ''' <remarks></remarks>
    ReadOnly Property MaxMemoryLineNumber() As Integer
        Get
            Return MemoryLines.Count
        End Get
    End Property
    ''' <summary>
    ''' 最大真实行数
    ''' </summary>
    ''' <remarks></remarks>
    ReadOnly Property MaxRealLineNumber() As Integer
        Get
            Return ExRealLineManager.Count
        End Get
    End Property
    ''' <summary>
    ''' 最大真实行数
    ''' </summary>
    ''' <remarks></remarks>
    ReadOnly Property MaxDisplayLineNumber() As Integer
        Get
            Return ExDisplayManager.Count
        End Get
    End Property
    ''' <summary>
    ''' 获得指定内存行对象
    ''' </summary>
    ''' <param name="LineNumber"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function GetMemoryLine(ByVal LineNumber As Integer) As Line
        Return MemoryLines(LineNumber - 1)
    End Function
    ''' <summary>
    ''' 通过显示行号获得内存行对象
    ''' </summary>
    ''' <param name="LineNumber"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function GetMemoryLineByDisplayLineNumber(ByVal LineNumber As Integer) As Line
        Return MemoryLines(ExDisplayManager.GetMemoryNoByDisplayNo(LineNumber) - 1)
    End Function
    ''' <summary>
    ''' 获得当前内存行对象
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function GetCurrentDisplayLine() As Line
        Return MemoryLines(ExDisplayManager.GetMemoryNoByDisplayNo(mDisplayPosition.Y) - 1)
    End Function
    ''' <summary>
    ''' 获得真实行文本
    ''' </summary>
    ''' <param name="RealLineNumber"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function GetRealLineText(ByVal RealLineNumber As Integer) As String
        Dim strRtn As String = String.Empty
        For i As Integer = ExRealLineManager.GetInfoLine(RealLineNumber).Real_MemoryStartLineNo To _
                           ExRealLineManager.GetInfoLine(RealLineNumber).Real_MemoryEndLineNo
            strRtn &= MemoryLines(i - 1).Text
        Next
        Return strRtn
    End Function
    Function GetDisplayLineByRealLine(ByVal RealLineNumber As Integer) As Integer
        Return ExDisplayManager.GetDisplayNoByMemoryNo(ExRealLineManager.GetInfoLine(RealLineNumber).Real_MemoryStartLineNo)
    End Function
    ''' <summary>
    ''' 当前行的文本
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    ReadOnly Property CurrentLineText() As String
        Get
            Return GetMemoryLineByDisplayLineNumber(mDisplayPosition.Y).Text
        End Get
    End Property
    ''' <summary>
    ''' 当前行的首行的信息
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function GetCurrentHeaderLineInfo() As Line
        Return ExRealLineManager.GetInfoLine(GetCurrentDisplayLine.Dis_RealLineNumber)
    End Function
    ''' <summary>
    ''' 根据表示点计算插入点
    ''' </summary>
    ''' <param name="DisplayPos"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function GetInputPosByDisplayPos(ByVal DisplayPos As Point) As Point
        Dim RtnPoint As Point
        Dim mLine As Line = GetMemoryLineByDisplayLineNumber(DisplayPos.Y)
        Dim XPos As Integer = DisplayPos.X
        If mLine.Dis_IsFirstLine = False Then
            '统计前面各个子行的字数
            For i As Integer = 1 To mLine.Dis_CurrentLineNo - 1
                XPos += GetMemoryLineByDisplayLineNumber(DisplayPos.Y - i).Text.Length
            Next
        End If
        RtnPoint = New Point(XPos, mLine.Dis_RealLineNumber)
        Return RtnPoint
    End Function
    ''' <summary>
    ''' 根据插入点计算表示点
    ''' </summary>
    ''' <param name="InputPos"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function GetDisplayPosByInputPos(ByVal InputPos As Point) As Point
        Dim RtnPoint As Point
        Dim TempPoint As Point = ExRealLineManager.GetMemPosByRealPos(InputPos)
        Dim XPos As Integer = TempPoint.X
        Dim YPos As Integer = ExDisplayManager.GetDisplayNoByMemoryNo(TempPoint.Y)
        RtnPoint = New Point(XPos, YPos)
        Return RtnPoint
    End Function
#End Region
#Region "其他"
    ''' <summary>
    ''' 获取当前输入位置的最后一个词语，用来作为自动补完的词根
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function GetLastWord() As String
        Dim rtnString As String = String.Empty
        If InputPosition.X > 1 Then
            Dim i As Integer
            For i = InputPosition.X - 1 To 1 Step -1
                If Mid(GetMemoryLine(InputPosition.Y).Text, i, 1) = Space(1) Then Exit For
            Next
            If i = 0 Then i = 1
            rtnString = Mid(GetMemoryLine(InputPosition.Y).Text, i, InputPosition.X - i).Trim
        End If
        Return rtnString
    End Function
    ''' <summary>
    ''' 使指定行可见
    ''' </summary>
    ''' <param name="RealLineNumber"></param>
    ''' <remarks>Jump命令调用前使用</remarks>
    Sub MakeLineVisible(ByVal RealLineNumber As Integer)
        If ExRealLineManager.GetInfoLine(RealLineNumber).Real_IsHidden Then
            For i As Integer = RealLineNumber To 1 Step -1
                If ExRealLineManager.GetInfoLine(i).Real_IsBlockHeader And ExRealLineManager.GetInfoLine(i).Real_IsFolder Then
                    Expend(ExDisplayManager.GetDisplayNoByMemoryNo(ExRealLineManager.GetInfoLine(i).Real_MemoryStartLineNo))
                End If
            Next
        End If
    End Sub
#End Region
#Region "构造器"
    Sub New(ByVal DocEncoding As Encoding)
        '新建文档类的时候，添加第一个行
        Dim InitLine As New Line
        InitLine.Dis_IsFirstLine = True
        InitLine.Dis_IsLastLine = True
        InitLine.Dis_RealLineNumber = 1
        InitLine.Dis_CurrentLineNo = 1
        InitLine.Dis_TotalCount = 1
        InitLine.Real_MemoryStartLineNo = 1
        InitLine.Real_MemoryEndLineNo = 1
        MemoryLines.Add(InitLine)

        ExDisplayManager = New DisplayLineManager
        ExDisplayManager.Add(1)

        ExRealLineManager = New RealLineManager
        ExRealLineManager.Add(1)

        mEncoding = DocEncoding
        InputPosition = New Point(1, 1)
        DisplayPosition = New Point(1, 1)
    End Sub
#End Region
#Region "文件操作"
    ''' <summary>
    ''' 从外部读入一个文件
    ''' </summary>
    ''' <param name="FileName">文件名</param>
    ''' <param name="FileEncoding">文件编码</param>
    ''' <remarks></remarks>
    Public Sub LoadFile(ByVal FileName As String, ByVal FileEncoding As System.Text.Encoding)
        Dim mFileOpen As New StreamReader(FileName, FileEncoding)
        Dim strLine As String
        mEncoding = FileEncoding
        MaxWidth = 0
        MaxWidthLines.Clear()
        MemoryLines.Clear()
        ExDisplayManager.Clear()
        ExRealLineManager.Clear()
        Do While True
            strLine = mFileOpen.ReadLine()
            '注意：If strLine <> Nothing Then 这样的写法，如果遇到空行的话，会跳出循环的！
            If Not strLine Is Nothing Then
                Dim NewLine As New Line(strLine)
                NewLine.Dis_IsFirstLine = True
                NewLine.Dis_IsLastLine = True
                NewLine.Dis_RealLineNumber = MemoryLines.Count + 1
                NewLine.Dis_CurrentLineNo = 1
                NewLine.Dis_TotalCount = 1
                NewLine.Real_MemoryStartLineNo = MemoryLines.Count + 1
                NewLine.Real_MemoryEndLineNo = MemoryLines.Count + 1
                MemoryLines.Add(NewLine)
                ExRealLineManager.Add(MemoryLines.Count)
                ExDisplayManager.Add(MemoryLines.Count)
            Else
                Exit Do
            End If
        Loop
        mFileOpen.Close()
        If MaxMemoryLineNumber = 0 Then
            '如果打开空文件的时候
            MemoryLines.Add(New Line)
        End If
        '注意，如果使用ReadToEnd的话，然后在用Split（vbcrlf）来获取文字数组，会有奇怪的换行在每行文字里！！！！
        Me.InputPosition = New Point(1, 1)
        Me.DisplayPosition = New Point(1, 1)
        '重置所有标志位
        ResetFlags()
    End Sub
    ''' <summary>
    ''' 保存文件[使用指定编码]
    ''' </summary>
    ''' <param name="FileName">文件名</param>
    ''' <param name="FileEnCoding">文件编码</param>
    ''' <remarks></remarks>
    Public Sub SaveFile(ByVal FileName As String, ByVal FileEnCoding As System.Text.Encoding)
        mEncoding = FileEnCoding
        SaveFile(FileName)
    End Sub
    ''' <summary>
    ''' 保存文件[使用打开文件时候的编码]
    ''' </summary>
    ''' <param name="FileName">文件名</param>
    ''' <remarks></remarks>
    Public Sub SaveFile(ByVal FileName As String)
        Dim mFileSave As New StreamWriter(FileName, False, mEncoding)
        '恢复原本文件状态
        If ExWordWrapMode Then
            UnDoWrapWord()
        End If
        '保存文件
        For i As Integer = 1 To MaxMemoryLineNumber
            mFileSave.WriteLine(GetMemoryLine(i).Text)
        Next
        mFileSave.Close()
        '恢复折行显示状态
        If ExWordWrapMode Then
            DoWrapWord(WordWrapWidth)
        End If
    End Sub
#End Region
#Region "插入系"
    ''' <summary>
    ''' 将一个字符串用插入方式输入到指定行的指定位置的后面
    ''' </summary>
    ''' <param name="InsertChar">指定字符串</param>
    ''' <param name="IsAddToStep">是否加入撤销队列</param>
    ''' <remarks>注意：列位置为插入字符的第一个字的位置</remarks>
    Sub InsertChar(ByVal InsertChar As String, Optional ByVal IsAddToStep As Boolean = True)
        If ExColumnMode Then
            '列模式
            If ColumnModeList.Count > 0 Then
                Dim NewStep As StepManager.StruStep()
                ReDim NewStep(ColumnModeList.Count - 1)
                For i As Integer = FirstColumnLine To LastColumnLine
                    InputPosition = New Point(ColumnModeList.Item(i), i)
                    With NewStep(i - FirstColumnLine)
                        .Action = StepManager.StepName.ColumnInsertChar
                        .Pos = InputPosition
                        .Text = InsertChar
                        .NewText = ""
                    End With
                    atomic_InsertString(InputPosition, InsertChar)
                    ColumnModeList.Item(i) += InsertChar.Length
                Next
                If IsAddToStep Then StepList.Add(NewStep, StepManager.StepName.ColumnInsertChar, FirstColumnLine, LastColumnLine)
            End If
        Else
            Dim NewStep As StepManager.StruStep
            With NewStep
                .Action = StepManager.StepName.InsertChar
                .Pos = InputPosition
                .Text = InsertChar
                .NewText = ""
            End With
            If IsAddToStep Then StepList.Add(NewStep)
            atomic_InsertString(InputPosition, InsertChar)
        End If
    End Sub
    ''' <summary>
    ''' 在指定的行中添加一个换行
    ''' </summary>
    ''' <remarks>行号从1开始</remarks>
    Sub InsertEnter(Optional ByVal IsAddToStep As Boolean = True)
        '列模式的时候，不进行操作    
        If ExColumnMode Then Exit Sub
        '插入一个空行
        Dim NewStep As StepManager.StruStep
        With NewStep
            .Action = StepManager.StepName.InsertEnter
            .Pos = InputPosition
            .Text = ""
            .NewText = ""
        End With
        If IsAddToStep Then StepList.Add(NewStep)
        atomic_DivideLine(InputPosition)
    End Sub
    ''' <summary>
    ''' 在指定行中插入文本
    ''' </summary>
    ''' <param name="strSelection">插入文本</param>
    ''' <param name="IsAddToStep">是否加入撤销队列</param>
    ''' <remarks></remarks>
    Sub InsertSelection(ByVal strSelection As String, Optional ByVal IsAddToStep As Boolean = True)
        '所有的操作，都必须基于原子操作。
        Dim strArray() As String = Split(strSelection, vbCrLf)
        Select Case strArray.Length
            Case 1
                Dim NewStep As StepManager.StruStep
                With NewStep
                    .Action = StepManager.StepName.InsertChar
                    .Pos = InputPosition
                    .Text = strSelection
                    .NewText = ""
                End With
                If IsAddToStep Then StepList.Add(NewStep)
                atomic_InsertString(InputPosition, strSelection)
            Case 2
                Dim NewStep As StepManager.StruStep
                With NewStep
                    .Action = StepManager.StepName.InsertSelection
                    .Pos = InputPosition
                    .Text = strSelection
                    .NewText = ""
                End With
                If IsAddToStep Then StepList.Add(NewStep)
                atomic_InsertString(InputPosition, strArray(0))
                atomic_DivideLine(InputPosition)
                atomic_InsertString(InputPosition, strArray(1))
                InputPosition = New Point(InputPosition.X, InputPosition.Y + strArray.Length - 2)
            Case Else
                Dim NewStep As StepManager.StruStep
                With NewStep
                    .Action = StepManager.StepName.InsertSelection
                    .Pos = InputPosition
                    .Text = strSelection
                    .NewText = ""
                End With
                If IsAddToStep Then StepList.Add(NewStep)
                atomic_InsertString(InputPosition, strArray(0))
                atomic_DivideLine(InputPosition)
                atomic_InsertString(InputPosition, strArray(strArray.Length - 1))
                Dim InsertString As String()
                ReDim InsertString(strArray.Length - 3)
                For i As Integer = 1 To strArray.Length - 2
                    InsertString(i - 1) = strArray(i)
                Next
                'atomic_DivideLine对于InputPosition发生修改
                atomic_InsertMulitLines(InputPosition.Y, InsertString)
                InputPosition = New Point(InputPosition.X, InputPosition.Y + strArray.Length - 2)
                DisplayPosition = GetDisplayPosByInputPos(InputPosition)
        End Select
    End Sub
#End Region
#Region "更新系"
    ''' <summary>
    ''' 将一个字符串用变更方式输入到指定行的指定位置的后面
    ''' </summary>
    ''' <param name="strUpdateChar">指定字符串</param>
    ''' <remarks>注意：列位置为插入字符的第一个字的位置</remarks>
    Sub UpdateChar(ByVal strUpdateChar As String, Optional ByVal IsAddToStep As Boolean = True)
        Dim NewStep As StepManager.StruStep
        With NewStep
            .Action = StepManager.StepName.UpdateChar
            .Pos = InputPosition
            .Text = Mid(CurrentLineText, InputPosition.X, 1)
            .NewText = strUpdateChar
        End With
        If IsAddToStep Then StepList.Add(NewStep)
        atomic_UpdateChar(InputPosition, strUpdateChar)
    End Sub
    ''' <summary>
    ''' 更新选中区域文字
    ''' </summary>
    ''' <param name="StrText"></param>
    ''' <remarks></remarks>
    Sub UpdateSelectionText(ByVal StrText As String, Optional ByVal IsAddToStep As Boolean = True)
        Dim NewStep As StepManager.StruStep
        With NewStep
            .Action = StepManager.StepName.UpdateSection
            .Pos = SelectStartRealPos
            .Text = GetSelectionText()
            .NewText = StrText
        End With
        If IsAddToStep Then StepList.Add(NewStep)
        DeleteSelection(False)
        InsertSelection(StrText, False)
    End Sub
#End Region
#Region "删除系"
    ''' <summary>
    ''' 从指定位置删除一个字符,返回值为是否造成换行
    ''' </summary>
    ''' <param name="Direction">删除方向</param>
    ''' <param name="IsAddToStep">是否加入撤销队列</param>
    ''' <returns>是否造成了换行</returns>
    ''' <remarks></remarks>
    Function DeleteChar(ByVal Direction As Boolean, Optional ByVal IsAddToStep As Boolean = True) As Boolean
        '原来的字符串
        If Direction Then
            '删除
            Return DelAction(IsAddToStep)
        Else
            '后退
            Return BackSpaceAction(IsAddToStep)
        End If
    End Function
    ''' <summary>
    ''' 删除[含列操作]
    ''' </summary>
    ''' <param name="IsAddToStep"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function DelAction(ByVal IsAddToStep As Boolean) As Boolean
        Dim strCurrent As String
        If ExColumnMode Then
            '列模式
            If ColumnModeList.Count > 0 Then
                Dim NewStep As StepManager.StruStep()
                ReDim NewStep(ColumnModeList.Count - 1)
                For i As Integer = FirstColumnLine To LastColumnLine
                    InputPosition = New Point(ColumnModeList.Item(i), i)
                    strCurrent = GetMemoryLine(DisplayPosition.Y).Text
                    With NewStep(i - FirstColumnLine)
                        If InputPosition.X <> strCurrent.Length + 1 Then
                            .Action = StepManager.StepName.ColumnDelCharByDel
                            .Pos = InputPosition
                            .Text = Mid(GetMemoryLineByDisplayLineNumber(DisplayPosition.Y).Text, DisplayPosition.X, 1)
                            .NewText = ""
                            atomic_DeleteChar(InputPosition)
                        Else
                            .Action = StepManager.StepName.None
                            .Pos = InputPosition
                            .Text = ""
                            .NewText = ""
                        End If
                    End With
                Next
                If IsAddToStep Then StepList.Add(NewStep, StepManager.StepName.ColumnDelCharByDel, FirstColumnLine, LastColumnLine)
                Return True
            End If
        Else
            Dim NewStep As StepManager.StruStep
            strCurrent = GetMemoryLineByDisplayLineNumber(DisplayPosition.Y).Text
            If DisplayPosition.X = strCurrent.Length + 1 Then
                '如果是最后一个字符后的话，不是文章的末尾
                If MaxDisplayLineNumber > DisplayPosition.Y Then
                    '已经是行尾的时候，将下一行追加到这行的后部，需要重新绘制
                    With NewStep
                        .Action = StepManager.StepName.MegerLine
                        .Pos = InputPosition
                        .Text = ""
                        .NewText = ""
                    End With
                    If IsAddToStep Then StepList.Add(NewStep)
                    atomic_MergeLine(InputPosition.Y)
                    Return True
                End If
            Else
                With NewStep
                    .Action = StepManager.StepName.DeleteCharByDel
                    .Pos = InputPosition
                    .Text = Mid(GetMemoryLine(InputPosition.Y).Text, InputPosition.X, 1)
                    .NewText = ""
                End With
                If IsAddToStep Then StepList.Add(NewStep)
                atomic_DeleteChar(InputPosition)
            End If
        End If
    End Function
    ''' <summary>
    ''' 后退[含列操作]
    ''' </summary>
    ''' <param name="IsAddToStep"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function BackSpaceAction(ByVal IsAddToStep As Boolean) As Boolean
        Dim strCurrent As String
        If ExColumnMode Then
            '列模式
            If ColumnModeList.Count > 0 Then
                Dim NewStep As StepManager.StruStep()
                ReDim NewStep(ColumnModeList.Count - 1)
                For i As Integer = FirstColumnLine To LastColumnLine
                    InputPosition = New Point(ColumnModeList.Item(i), i)
                    strCurrent = GetMemoryLine(InputPosition.Y).Text
                    With NewStep(i - FirstColumnLine)
                        If InputPosition.X <> 1 Then
                            InputPosition = New Point(ColumnModeList.Item(i) - 1, i)
                            .Action = StepManager.StepName.ColumnDelCharByBS
                            .Pos = InputPosition
                            .Text = Mid(GetMemoryLineByDisplayLineNumber(DisplayPosition.Y).Text, InputPosition.X, 1)
                            .NewText = ""
                            atomic_DeleteChar(InputPosition)
                            ColumnModeList.Item(i) -= 1
                        Else
                            .Action = StepManager.StepName.None
                            .Pos = InputPosition
                            .Text = ""
                            .NewText = ""
                        End If
                    End With
                Next
                If IsAddToStep Then StepList.Add(NewStep, StepManager.StepName.ColumnDelCharByBS, FirstColumnLine, LastColumnLine)
                Return True
            End If
        Else
            Dim NewStep As StepManager.StruStep
            strCurrent = GetMemoryLine(DisplayPosition.Y).Text
            If DisplayPosition.X = 1 Then
                '如果是第一个字符，且不是首行
                If DisplayPosition.Y > 1 Then
                    '将这行信息放在上一行的尾部
                    With NewStep
                        .Action = StepManager.StepName.MegerLine
                        '合并点是上一行的行尾处
                        .Pos = New Point(GetMemoryLineByDisplayLineNumber(DisplayPosition.Y - 1).Text.Length + 1, DisplayPosition.Y - 1)
                        .Text = ""
                        .NewText = ""
                    End With
                    If IsAddToStep Then StepList.Add(NewStep)
                    atomic_MergeLine(InputPosition.Y - 1)
                    Return True
                End If
            Else
                '后退删除可以分解为将输入点向前一位,然后删除一个字符
                DisplayPosition = New Point(DisplayPosition.X - 1, DisplayPosition.Y)
                With NewStep
                    .Action = StepManager.StepName.DeleteCharByBS
                    .Pos = InputPosition
                    .Text = Mid(GetMemoryLineByDisplayLineNumber(InputPosition.Y).Text, InputPosition.X, 1)
                    .NewText = ""
                End With
                If IsAddToStep Then StepList.Add(NewStep)
                atomic_DeleteChar(InputPosition)
            End If
        End If
    End Function
    ''' <summary>
    ''' 删除选中部分
    ''' </summary>
    ''' <param name="IsAddToStep"></param>
    ''' <returns>是否需要重新绘制</returns>
    ''' <remarks>自动更新插入点</remarks>
    Function DeleteSelection(Optional ByVal IsAddToStep As Boolean = True) As Boolean
        '确定选中行的第一行
        Dim RealDelStartNo As Integer = SelectStartRealPos.Y
        '确定选中行的最后一行
        Dim RealDelEndNo As Integer = SelectEndRealPos.Y
        '撤销队列中添加的步骤
        Dim NewStep As StepManager.StruStep
        Dim DelMemStart As Integer = ExRealLineManager.GetInfoLine(RealDelStartNo).Real_MemoryStartLineNo
        Dim DelMemEnd As Integer = ExRealLineManager.GetInfoLine(RealDelEndNo).Real_MemoryEndLineNo
        '************************************
        '*   如果选中部分只涉及到单行的话
        '************************************
        If RealDelStartNo = RealDelEndNo Then
            Dim IsWholeSelected As Boolean = True
            For i As Integer = DelMemStart To DelMemEnd
                If GetMemoryLine(DelMemStart).IsWholeSelected = False Then
                    IsWholeSelected = False
                    Exit For
                End If
            Next
            If IsWholeSelected Then
                '不能使用DeleteLine,这里只是将行内容清空，但是不删除这个行
                NewStep.Pos = New Point(1, RealDelStartNo)
                NewStep.Action = StepManager.StepName.DeleteCharByDel
                NewStep.Text = GetSelectionText()
                NewStep.NewText = ""
                If IsAddToStep Then StepList.Add(NewStep)
                atomic_ChangeWholeLine(RealDelStartNo, "")
            Else
                NewStep.Pos = SelectStartRealPos
                NewStep.Action = StepManager.StepName.DeleteCharByDel
                NewStep.Text = GetSelectionText()
                NewStep.NewText = ""
                If IsAddToStep Then StepList.Add(NewStep)
                atomic_DeleteString(SelectStartRealPos, Mid(GetRealLineText(RealDelStartNo), SelectStartRealPos.X, SelectEndRealPos.X - SelectStartRealPos.X))
            End If
            ExRealLineManager.UnSelectAll(RealDelStartNo)
        Else
            '************************************
            '*      如果涉及到复数行的话
            '************************************
            '0.首行和尾行都部分选中
            '1.首行整行，尾行部分
            '2.尾行整行，首行部分
            '3.首行和尾行都是选中整行吗？
            Dim SelFlg As Byte = 0

            If ExRealLineManager.IsSelectWholeLine(RealDelStartNo) Then SelFlg += 1
            If ExRealLineManager.IsSelectWholeLine(RealDelEndNo) Then SelFlg += 2

            Dim DelCount As Integer = RealDelEndNo - RealDelStartNo
            NewStep.Pos = SelectStartRealPos
            NewStep.Action = StepManager.StepName.DeleteSelection
            NewStep.Text = GetSelectionText()
            NewStep.NewText = ""
            If IsAddToStep Then StepList.Add(NewStep)
            Select Case SelFlg
                Case 0
                    '首尾合并，中间删除
                    Dim Newstr As String = String.Empty
                    Newstr = Mid(GetRealLineText(RealDelStartNo), 1, SelectStartRealPos.X - 1)
                    Newstr &= Mid(GetRealLineText(RealDelEndNo), SelectEndRealPos.X)
                    atomic_ChangeWholeLine(RealDelStartNo, Newstr)
                    atomic_DeleteMulitLine(RealDelStartNo + 1, DelCount)
                Case 1
                    '首行整行，尾行部分
                    DelCount = RealDelEndNo - RealDelStartNo
                    atomic_ChangeWholeLine(RealDelStartNo, Mid(GetRealLineText(RealDelEndNo), SelectEndRealPos.X))
                    atomic_DeleteMulitLine(RealDelStartNo + 1, DelCount)
                Case 2
                    '尾行整行，首行部分
                    DelCount = RealDelEndNo - RealDelStartNo
                    atomic_ChangeWholeLine(RealDelStartNo, Mid(GetRealLineText(RealDelStartNo), 1, SelectStartRealPos.X - 1))
                    atomic_DeleteMulitLine(RealDelStartNo + 1, DelCount)
                Case 3
                    '整行删除
                    atomic_ChangeWholeLine(RealDelEndNo, "")
                    DelCount = RealDelEndNo - RealDelStartNo
                    atomic_DeleteMulitLine(RealDelStartNo, DelCount)
            End Select
        End If
        '设置插入点
        DisplayPosition = GetDisplayPosByInputPos(SelectStartRealPos)
        '清除选中区域
        ClearSelection()
        If DelMemStart = DelMemEnd Then
            Return False
        Else
            Return True
        End If
    End Function
    ''' <summary>
    ''' 箱型选中区域的删除
    ''' </summary>
    ''' <param name="IsAddToStep"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function DeleteBoxSelection(Optional ByVal IsAddToStep As Boolean = True) As Boolean
        '撤销队列中添加的步骤
        Dim NewStep As StepManager.StruStep()
        ReDim NewStep(SelectEndRealPos.Y - SelectStartRealPos.Y)
        For TempCount As Integer = SelectStartRealPos.Y To SelectEndRealPos.Y
            With GetMemoryLine(TempCount)
                If GetMemoryLine(TempCount).SelectStart <> 0 Then
                    '如果有选中部分的话
                    With NewStep(TempCount - SelectStartRealPos.Y)
                        .Action = StepManager.StepName.BoxDelete
                        .Pos = New Point(GetMemoryLine(TempCount).SelectStart, TempCount)
                        .Text = GetMemoryLine(TempCount).Selection
                    End With
                    atomic_DeleteString(New Point(.SelectStart, TempCount), .SelectLength)
                End If
            End With
        Next
        If IsAddToStep Then StepList.Add(NewStep, StepManager.StepName.BoxDelete, SelectStartRealPos.Y, SelectEndRealPos.Y)
        ClearSelection()
        Return True
    End Function
#End Region
#Region "替换和查找"
    ''' <summary>
    ''' 在行里设置高亮关键字
    ''' </summary>
    ''' <param name="strKeyWord"></param>
    ''' <remarks></remarks>
    Sub SetHeightLightWord(ByVal strKeyWord As String)
        mHeightLightWord = strKeyWord
        For i As Integer = 1 To MaxMemoryLineNumber
            GetMemoryLine(i).ResetHeightLightWord(mHeightLightWord)
        Next
    End Sub
    Public SearchKeyWord As String
    Function Find(ByVal KeyWord As String, ByVal Directory As Boolean) As Boolean
        SetSerachKey(KeyWord)
        If Directory Then
            Return FindNext()
        Else
            Return FindPre()
        End If
    End Function
    Sub SetSerachKey(ByVal strKeyWord As String)
        SearchKeyWord = strKeyWord
        For i As Integer = 1 To MaxMemoryLineNumber
            GetMemoryLine(i).ResetSearchKeyWord(strKeyWord)
        Next
    End Sub
    ''' <summary>
    ''' 查找下一个
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function FindNext() As Boolean
        Dim rtn As Boolean = False
        For mCount As Integer = InputPosition.Y To MaxMemoryLineNumber
            With GetMemoryLine(mCount)
                If .HasSearchWord Then
                    '如果有关键字，比较一下关键字和现在的插入点的位置
                    For i As Integer = 0 To .WordList.Count - 1
                        If Mid(.Text, .WordList(i).StartPos, .WordList(i).Length) = SearchKeyWord Then
                            '如果发现关键字
                            If mCount = InputPosition.Y Then
                                '如果是同一行的情况
                                If .WordList(i).StartPos >= InputPosition.X Then
                                    '如果开始位置比现在位置靠后
                                    ClearSelection()
                                    SelectStartRealPos = New Point(.WordList(i).StartPos, mCount)
                                    SelectEndRealPos = New Point(.WordList(i).StartPos + .WordList(i).Length, mCount)
                                    Me.UpdateSelection(SelectStartRealPos, SelectEndRealPos)
                                    Me.InputPosition = SelectEndRealPos
                                    rtn = True
                                    Exit For
                                End If
                            Else
                                '如果不是同一行的情况
                                ClearSelection()
                                SelectStartRealPos = New Point(.WordList(i).StartPos, mCount)
                                SelectEndRealPos = New Point(.WordList(i).StartPos + .WordList(i).Length, mCount)
                                Me.UpdateSelection(SelectStartRealPos, SelectEndRealPos)
                                Me.InputPosition = SelectEndRealPos
                                rtn = True
                                Exit For
                            End If
                        End If
                    Next
                End If
            End With
            If rtn Then Exit For
        Next
        Return rtn
    End Function
    ''' <summary>
    ''' 查找上一个
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function FindPre() As Boolean
        Dim rtn As Boolean = False
        For mCount As Integer = InputPosition.Y To 1 Step -1
            With GetMemoryLine(mCount)
                If .HasSearchWord Then
                    '如果有关键字，比较一下关键字和现在的插入点的位置
                    For i As Integer = .WordList.Count - 1 To 0 Step -1
                        If Mid(.Text, .WordList(i).StartPos, .WordList(i).Length) = SearchKeyWord Then
                            '如果发现关键字
                            If mCount = InputPosition.Y Then
                                '如果是同一行的情况
                                If .WordList(i).StartPos < InputPosition.X Then
                                    '如果开始位置比现在位置靠前
                                    ClearSelection()
                                    SelectStartRealPos = New Point(.WordList(i).StartPos, mCount)
                                    SelectEndRealPos = New Point(.WordList(i).StartPos + .WordList(i).Length, mCount)
                                    Me.UpdateSelection(SelectStartRealPos, SelectEndRealPos)
                                    Me.InputPosition = SelectStartRealPos
                                    rtn = True
                                    Exit For
                                End If
                            Else
                                '如果不是同一行的情况
                                ClearSelection()
                                SelectStartRealPos = New Point(.WordList(i).StartPos, mCount)
                                SelectEndRealPos = New Point(.WordList(i).StartPos + .WordList(i).Length, mCount)
                                Me.UpdateSelection(SelectStartRealPos, SelectEndRealPos)
                                Me.InputPosition = SelectStartRealPos
                                rtn = True
                                Exit For
                            End If
                        End If
                    Next
                End If
            End With
            If rtn Then Exit For
        Next
        Return rtn
    End Function
    Sub ReplaceAll(ByVal OldString As String, ByVal NewString As String)
        For i As Integer = 1 To MaxMemoryLineNumber
            GetMemoryLine(i).Replace(OldString, NewString)
        Next
    End Sub
#End Region
#Region "原子操作"
    '[统一使用InputPos作为参数，在方法内部，对于折行显示和普通模式做不同操作]
    ''' <summary>
    ''' 插入字符串(原子操作)
    ''' </summary>
    ''' <param name="InsertString">插入字符</param>
    ''' <param name="InputPos">插入点</param>
    ''' <remarks>自动更新插入点和文本</remarks>
    Private Sub atomic_InsertString(ByVal InputPos As Point, ByVal InsertString As String)
        '表示位置
        Dim DisplayPos As Point = GetDisplayPosByInputPos(InputPos)
        '原来的字符串
        Dim strCurrent As String = GetMemoryLineByDisplayLineNumber(DisplayPos.Y).Text
        '插入后的字符串
        Dim strAfterInsert As String
        '如果在普通显示的模式下
        If strCurrent = "" Then
            '如果原来为空行的话，直接插入
            strAfterInsert = InsertString
        Else
            '如果不为空行的话
            If strCurrent.Length + 1 = DisplayPos.X Then
                '如果原来字符长度的后一个位置为插入位置的话，直接添加在字符尾部
                strAfterInsert = strCurrent & InsertString
            Else
                '将字符插入到合适的位置
                strAfterInsert = Mid(strCurrent, 1, DisplayPos.X - 1) & InsertString & Mid(strCurrent, DisplayPos.X)
            End If
        End If
        '更新内存中的内容
        GetMemoryLineByDisplayLineNumber(DisplayPos.Y).Text = strAfterInsert
        If ExWordWrapMode Then
            '如果在折行显示的模式下
            Dim EditLine As Line = GetMemoryLineByDisplayLineNumber(DisplayPos.Y)
            If EditLine.Dis_IsLastLine = False Then
                '如果不是最后一行的话，必定要重新排版
                ReWrapLine(EditLine.Dis_RealLineNumber)
            Else
                If EditLine.Width > WordWrapWidth Then
                    '如果是最后一行，如果过于长的话，需要重新排版
                    ReWrapLine(EditLine.Dis_RealLineNumber)
                End If
            End If
        End If
        '代码折叠
        SetSyntax(InputPos.Y)
        '重新设置标志
        ResetFlags()
        '重新设置表示位置，用以重新表示光标
        DisplayPosition = New Point(DisplayPos.X + InsertString.Length, DisplayPos.Y)
    End Sub
    ''' <summary>
    ''' 插入一个真实行(原子操作)
    ''' </summary>
    ''' <param name="InsertlLineReaNo">插入后该行的真实行号</param>
    ''' <param name="strText">行文字</param>
    ''' <remarks>这个方法不改变插入点位置</remarks>
    Private Sub atomic_InsertLine(ByVal InsertlLineReaNo As Integer, ByVal strText As String)
        '无论什么理由，被插入的行，必然可见
        Dim NewLine As New Line(strText)
        '获得内存插入点位置
        Dim InsertMemoryNo As Integer
        If InsertlLineReaNo = 1 Then
            InsertMemoryNo = 1
        Else
            '上一个行的最后一个结束内存行的下一行
            InsertMemoryNo = ExRealLineManager.GetInfoLine(InsertlLineReaNo - 1).Real_MemoryEndLineNo + 1
        End If
        With NewLine
            .Dis_IsFirstLine = True
            .Dis_IsLastLine = True
            .Dis_CurrentLineNo = 1
            .Dis_TotalCount = 1
            .Dis_RealLineNumber = InsertlLineReaNo
            .Real_MemoryStartLineNo = InsertMemoryNo
            .Real_MemoryEndLineNo = InsertMemoryNo
        End With
        '加入内存列表
        '由于InsertIndex是内存行号，下面将 -1 来变为索引
        Me.MemoryLines.Insert(InsertMemoryNo - 1, NewLine)
        '更新表示行列表
        Dim LastLineDisplayEndNo As Integer
        If InsertlLineReaNo = MaxRealLineNumber + 1 Then
            LastLineDisplayEndNo = MaxDisplayLineNumber
        Else
            LastLineDisplayEndNo = ExDisplayManager.GetDisplayNoByMemoryNo(ExRealLineManager.GetInfoLine(InsertlLineReaNo - 1).Real_MemoryEndLineNo)
        End If
        If LastLineDisplayEndNo = 0 Then
            '如果上一条是非表示行的话
            For i = InsertlLineReaNo - 1 To 1 Step -1
                LastLineDisplayEndNo = ExDisplayManager.GetDisplayNoByMemoryNo(ExRealLineManager.GetInfoLine(i).Real_MemoryEndLineNo)
                If LastLineDisplayEndNo <> 0 Then Exit For
            Next
        End If
        Me.ExDisplayManager.Insert(LastLineDisplayEndNo + 1, InsertMemoryNo)
        '更新真实行列表
        Me.ExRealLineManager.Insert(InsertlLineReaNo, InsertMemoryNo)
        '更新所有内存行行号
        For i As Integer = InsertMemoryNo To MemoryLines.Count - 1
            With MemoryLines(i)
                .Dis_RealLineNumber += 1
                '增加的逻辑中，重新排版还没有进行，这里只需+1，
                .Real_MemoryStartLineNo += 1
                .Real_MemoryEndLineNo += 1
            End With
        Next
        '折行显示再处理
        If ExWordWrapMode Then
            ReWrapLine(InsertlLineReaNo)
        End If
        '代码折叠判断
        SetSyntax(InsertlLineReaNo)
        '对于删除行以下位置的书签的调整
        For i As Integer = 0 To lstBookMark.Count - 1
            If lstBookMark(i) >= InsertlLineReaNo Then lstBookMark(i) += 1
        Next
    End Sub
    ''' <summary>
    ''' 多行插入操作
    ''' </summary>
    ''' <param name="InsertAt">插入后该行的行号</param>
    ''' <param name="strText">插入文字块</param>
    ''' <remarks>这个方法不改变插入点位置</remarks>
    Private Sub atomic_InsertMulitLines(ByVal InsertAt As Integer, ByVal strText As String())
        Dim newlines As Integer = strText.Length
        For i As Integer = 0 To newlines - 1
            atomic_InsertLine(InsertAt + i, strText(i))
        Next
        '代码折叠
        ResetFlags()
    End Sub
    ''' <summary>
    ''' 删除一个字符(原子操作)
    ''' </summary>
    ''' <param name="InputPos">插入点</param>
    ''' <remarks>这个方法不改变插入点位置</remarks>
    Private Sub atomic_DeleteChar(ByVal InputPos As Point)
        Dim DisplayPos As Point = GetDisplayPosByInputPos(InputPos)
        '原来的字符串
        Dim strCurrent As String = GetMemoryLineByDisplayLineNumber(DisplayPos.Y).Text
        If DisplayPos.X = 1 Then
            GetMemoryLineByDisplayLineNumber(DisplayPos.Y).Text = Mid(strCurrent, 2)
        Else
            GetMemoryLineByDisplayLineNumber(DisplayPos.Y).Text = Mid(strCurrent, 1, DisplayPos.X - 1) & Mid(strCurrent, DisplayPos.X + 1)
        End If
        '代码折叠判断
        SetSyntax(InputPos.Y)
        '重新设置标志
        ResetFlags()
    End Sub
    ''' <summary>
    ''' 删除字符串(原子操作)
    ''' </summary>
    ''' <param name="InputPos">插入点</param>
    ''' <param name="strDel">删除字符串</param>
    ''' <remarks>这个方法不改变插入点位置</remarks>
    Private Sub atomic_DeleteString(ByVal InputPos As Point, ByVal strDel As String)
        Dim newstr As String
        newstr = Mid(GetRealLineText(InputPos.Y), 1, InputPos.X - 1)
        newstr &= Mid(GetRealLineText(InputPos.Y), InputPos.X + strDel.Length)
        atomic_ChangeWholeLine(InputPos.Y, newstr)
    End Sub
    ''' <summary>
    ''' 删除字符串(原子操作)
    ''' </summary>
    ''' <param name="InputPos">插入点</param>
    ''' <param name="strDelLength">删除字符串长度</param>
    ''' <remarks>这个方法不改变插入点位置</remarks>
    Private Sub atomic_DeleteString(ByVal InputPos As Point, ByVal strDelLength As Integer)
        If strDelLength = 0 Then Exit Sub
        Dim newstr As String
        newstr = Mid(GetMemoryLine(InputPos.Y).Text, 1, InputPos.X - 1)
        newstr &= Mid(GetMemoryLine(InputPos.Y).Text, InputPos.X + strDelLength)
        GetMemoryLine(InputPos.Y).Text = newstr
        '代码折叠
        ResetFlags()
    End Sub
    ''' <summary>
    ''' 删除一个真实行(原子操作)
    ''' </summary>
    ''' <param name="DeleteFrom">删除行号</param>
    ''' <remarks>自动更新插入点</remarks>
    Private Sub atomic_DeleteLine(ByVal DeleteFrom As Integer)
        '从内存中删除
        Dim DelMemStart As Integer
        Dim DelCount As Integer
        DelMemStart = ExRealLineManager.GetInfoLine(DeleteFrom).Real_MemoryStartLineNo
        DelCount = ExRealLineManager.GetInfoLine(DeleteFrom).Real_MemoryEndLineNo - _
                   ExRealLineManager.GetInfoLine(DeleteFrom).Real_MemoryStartLineNo + 1
        For i As Integer = 1 To DelCount
            MemoryLines.RemoveAt(DelMemStart - 1)
        Next
        '更新表示内容
        Dim DispDelStart As Integer = ExDisplayManager.GetDisplayNoByMemoryNo(DelMemStart)
        If DispDelStart <> 0 Then
            '如果原先就是表示的行
            ExDisplayManager.RemoveLinesByDelLine(DispDelStart, DelCount, DisplayLineManager.JustfiyMode.ALL)
        Else
            '如果原先就不是表示的行
            For i As Integer = DelMemStart To MaxMemoryLineNumber
                DispDelStart = ExDisplayManager.GetDisplayNoByMemoryNo(i)
                If DispDelStart <> 0 Then Exit For
            Next
            ExDisplayManager.RemoveLinesByDelLine(DispDelStart, DelCount, DisplayLineManager.JustfiyMode.ProcessRemainLine)
        End If
        '更新真实行列表
        ExRealLineManager.RemoveAt(DeleteFrom, DelCount)
        '更新所有内存行行号
        For i As Integer = DelMemStart - 1 To MemoryLines.Count - 1
            With MemoryLines(i)
                .Dis_RealLineNumber -= 1
                '删除的逻辑，将排版好的东西删除掉，需要 - DelCount
                .Real_MemoryStartLineNo -= DelCount
                .Real_MemoryEndLineNo -= DelCount
            End With
        Next
        '如果是书签行的话，从书签中除去
        If lstBookMark.Contains(DeleteFrom) Then
            lstBookMark.Remove(DeleteFrom)
        End If
        '对于删除行以下位置的书签的调整
        For i As Integer = 0 To lstBookMark.Count - 1
            If lstBookMark(i) > DeleteFrom Then lstBookMark(i) -= 1
        Next
    End Sub
    ''' <summary>
    ''' 删除多行
    ''' </summary>
    ''' <param name="DelFrom">开始行号</param>
    ''' <param name="delcount">行数</param>
    ''' <remarks></remarks>
    Private Sub atomic_DeleteMulitLine(ByVal DelFrom As Integer, ByVal delcount As Integer)
        For i As Integer = 1 To delcount
            atomic_DeleteLine(DelFrom)
        Next
        '代码折叠
        ResetFlags()
    End Sub
    ''' <summary>
    ''' 更新单个字符(原子操作)
    ''' </summary>
    ''' <param name="strUpdateChar">单个字符</param>
    ''' <param name="InputPos">插入点</param>
    ''' <remarks>只能用来更新单个字符！！自动更新插入点和文本</remarks>
    Private Sub atomic_UpdateChar(ByVal InputPos As Point, ByVal strUpdateChar As String)
        '原来的字符串
        Dim strCurrent As String = GetRealLineText(InputPos.Y)
        '插入后的字符串
        Dim strAfterInsert As String
        If strCurrent = "" Then
            '如果原来为空行的话，直接插入
            strAfterInsert = strUpdateChar
        Else
            '如果不为空行的话
            If strCurrent.Length + 1 = InputPos.X Then
                '如果原来字符长度的后一个位置为插入位置的话，直接添加在字符尾部
                strAfterInsert = strCurrent & strUpdateChar
            Else
                '将字符插入到合适的位置
                strAfterInsert = Mid(strCurrent, 1, InputPos.X - 1) & strUpdateChar & Mid(strCurrent, InputPos.X + 1)
            End If
        End If
        atomic_ChangeWholeLine(InputPos.Y, strAfterInsert)
        InputPosition = New Point(InputPos.X + strUpdateChar.Length, InputPos.Y)
        DisplayPosition = GetDisplayPosByInputPos(InputPosition)
        '代码折叠判断
        SetSyntax(InputPos.Y)
        '重新设置标志
        ResetFlags()
    End Sub
    ''' <summary>
    ''' 整行文本变更
    ''' </summary>
    ''' <param name="RealLineNo">行号</param>
    ''' <param name="NewText">新文本</param>
    ''' <remarks>这个方法不改变插入点位置</remarks>
    Private Sub atomic_ChangeWholeLine(ByVal RealLineNo As Integer, ByVal NewText As String)
        atomic_DeleteLine(RealLineNo)
        atomic_InsertLine(RealLineNo, NewText)
        '代码折叠
        SetSyntax(RealLineNo)
        ResetFlags()
    End Sub
    ''' <summary>
    ''' 分割一个行(原子操作)
    ''' </summary>
    ''' <param name="InputPos">插入点</param>
    ''' <remarks>自动更新插入点和文本</remarks>
    Private Sub atomic_DivideLine(ByVal InputPos As Point)
        If ExRealLineManager.GetInfoLine(InputPos.Y).Real_IsBlockHeader And _
           ExRealLineManager.GetInfoLine(InputPos.Y).Real_IsFolder Then
            '如果这一个合并行是折叠代码段的话
            If InputPos.X = 1 Then
                atomic_InsertLine(InputPos.Y, String.Empty)
                '代码折叠
                ResetFlags()
                Exit Sub
            Else
                '不然的话，先展开这个行
                Expend(GetDisplayPosByInputPos(InputPos).Y)
            End If
        End If
        Dim DisplayPos As Point = GetDisplayPosByInputPos(InputPos)
        '获得所在行的文本
        Dim strText As String
        If ExWordWrapMode Then
            '删除1个真实行，添加2个真实行。注意，这里需要调用重新对行进行排版的方法
            strText = GetRealLineText(InputPos.Y)
            atomic_DeleteLine(InputPos.Y)
            atomic_InsertLine(InputPos.Y, Mid(strText, 1, InputPos.X - 1))
            atomic_InsertLine(InputPos.Y + 1, Mid(strText, InputPos.X))
        Else
            strText = ExDocument.GetMemoryLineByDisplayLineNumber(DisplayPos.Y).Text
            ExDocument.GetMemoryLineByDisplayLineNumber(DisplayPos.Y).Text = Mid(strText, 1, DisplayPos.X - 1)
            SetSyntax(InputPos.Y)
            atomic_InsertLine(InputPos.Y + 1, Mid(strText, DisplayPos.X))
        End If
        DisplayPosition = New Point(1, DisplayPos.Y + 1)
        '代码折叠
        ResetFlags()
    End Sub
    ''' <summary>
    ''' 合并两个行(原子操作)
    ''' </summary>
    ''' <param name="FirstRealLineNo">第一个行的行号</param>
    ''' <remarks>自动更新插入点和文本</remarks>
    Public Sub atomic_MergeLine(ByVal FirstRealLineNo As Integer)
        Dim PosX As Integer = GetRealLineText(FirstRealLineNo).Length + 1
        If ExRealLineManager.GetInfoLine(FirstRealLineNo + 1).Real_IsBlockHeader And _
           ExRealLineManager.GetInfoLine(FirstRealLineNo + 1).Real_IsFolder Then
            '如果下一个合并行是折叠代码段的话
            If GetRealLineText(FirstRealLineNo) = String.Empty Then
                '如果这个行是空字符串，简单的删除这个行
                atomic_DeleteLine(FirstRealLineNo)
                '代码折叠
                ResetFlags()
                Exit Sub
            Else
                '不然的话，先展开这个行
                Expend(GetDisplayPosByInputPos(New Point(1, InputPosition.Y + 1)).Y)
            End If
        End If
        Dim strNewLine As String = GetRealLineText(FirstRealLineNo) + _
                                   ExDocument.GetRealLineText(FirstRealLineNo + 1)
        If ExWordWrapMode Then
            atomic_DeleteLine(FirstRealLineNo)
            atomic_DeleteLine(FirstRealLineNo)
            atomic_InsertLine(FirstRealLineNo, strNewLine)
        Else
            atomic_DeleteLine(FirstRealLineNo)
            ExRealLineManager.GetInfoLine(FirstRealLineNo).Text = strNewLine
            SetSyntax(FirstRealLineNo)
        End If
        'TODO：行的可见性 atomic_DeleteLine假设FirstLine + 1 为可见。
        InputPosition = New Point(PosX, FirstRealLineNo)
        DisplayPosition = GetDisplayPosByInputPos(InputPosition)
        '代码折叠
        ResetFlags()
    End Sub
#End Region
#Region "文档宽度计算"
    Sub ReSetWidth()
        MaxWidthLines.Clear()
        For intLines As Integer = 1 To MaxMemoryLineNumber
            GetMemoryLine(intLines).ReSetWidth()
        Next
    End Sub
    ''' <summary>
    ''' 计算文档中最大宽度
    ''' </summary>
    ''' <returns>最大宽度是否变化</returns>
    ''' <remarks></remarks>
    Public Function ResetMaxLineWidth() As Boolean
        '保存原来最大宽度的临时变量
        Dim mMaxWidth As Integer
        mMaxWidth = MaxWidth
        '重新计算最大宽度
        MaxWidth = 0
        For intLines As Integer = 1 To MaxMemoryLineNumber
            '如果该行宽度等于最大宽度，则将这行加入最大宽度行列表
            If GetMemoryLine(intLines).Width = MaxWidth Then
                MaxWidthLines.Add(intLines)
            End If
            '如果该行宽度大于最大宽度，重置最大宽度行列表和最大宽度
            If GetMemoryLine(intLines).Width > MaxWidth Then
                MaxWidthLines.Clear()
                MaxWidthLines.Add(intLines)
                MaxWidth = GetMemoryLine(intLines).Width
            End If
        Next
        If mMaxWidth <> MaxWidth Then Return True
    End Function
    ''' <summary>
    ''' 更新最大行宽列表
    ''' </summary>
    ''' <param name="LineNumber"></param>
    ''' <remarks></remarks>
    Public Function ResetMaxLineWidth(ByVal LineNumber As Integer) As Boolean
        Dim CurrentWidth As Integer = GetMemoryLine(LineNumber).Width
        '修改后的宽度和最大宽度一样，如果不在列表中，则加入列表
        If MaxWidth = CurrentWidth Then
            If Not MaxWidthLines.Contains(LineNumber) Then
                MaxWidthLines.Add(LineNumber)
            End If
            Return False
        End If
        '得到宽行的宽度，大于原来最大宽度
        If CurrentWidth > MaxWidth Then
            '清空最大行宽列表
            MaxWidthLines.Clear()
            '将当前行加入最大行宽列表
            MaxWidthLines.Add(LineNumber)
            MaxWidth = CurrentWidth
            Return True
        End If
        '如果修改行的宽度小于最大行宽
        If CurrentWidth < MaxWidth Then
            '如果原来在最大行宽里存在的行
            If MaxWidthLines.Contains(LineNumber) Then
                '移除该行
                MaxWidthLines.Remove(LineNumber)
                If MaxWidthLines.Count = 0 Then
                    '如果是行的列表，则重新获得列表
                    ResetMaxLineWidth()
                    Return True
                End If
            End If
        End If
        Return False
    End Function
#End Region
End Class

